package org.zcz.svnpackageutil;

import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

import java.io.*;
import java.nio.channels.FileChannel;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 协助svn打包工具
 */
public class SVNUtilTest {
    private static String projectName = PackageExecutor.projectConfig.projectName;// 工程名,多个请使用逗号隔开
    private static String url = PackageExecutor.projectConfig.url;// svn路径
    private static String projectPath =PackageExecutor.projectConfig.projectPath; // 项目本地路径
    private static String targetPackageFilePath = PackageExecutor.projectConfig.targetPackageFilePath+"\\";// 更新包目标目录

    // 过滤条件
    private static final String beginTime = PackageExecutor.Filter.beginTime; // 代码提交开始日期，不包含
    private static final String endTime = PackageExecutor.Filter.endTime; // 代码提交结束日期，不包含
    private static final String author = PackageExecutor.Filter.author;// 提交人
    private static long startRevision = PackageExecutor.Filter.startRevision;// 开始版本,包含
    private static long endRevision = PackageExecutor.Filter.endRevision;//表示最后一个版本，包含

    /**一下为约定配置，没有特殊需求，无需更改**/
    private static String buildPath = projectPath +"\\bytter_build";
    private static String classPathPer = "\\WEB-INF\\classes";
    private static SVNRepository repository = null;
    private static String packageNamePer = "";
    private static String packageName = "_"+PackageExecutor.packageName; // 更新包名称默认为日期，不用填写
    private static String readMe = "";// readMe中的内容，为代码提交的注释
    static {
        DateFormat format = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
        packageNamePer = format.format(new Date());
    }
    /**
     * svn连接初始化
     * @param projectUrl
     */
    public static void setupLibrary(String projectUrl) {
        DAVRepositoryFactory.setup();
        SVNRepositoryFactoryImpl.setup();
        FSRepositoryFactory.setup();
        try {
            repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(projectUrl));
        } catch (SVNException e) {
            e.printStackTrace();
        }
        // 身份验证
        ISVNAuthenticationManager authManager = SVNWCUtil.createDefaultAuthenticationManager(SVNConstant.User.name, SVNConstant.User.passWord);
        repository.setAuthenticationManager(authManager);
    }

    public static void main(String[] args) throws Exception {
        String[] projects = projectName.split(",");
        for (String project : projects){
            doMain(url+project.trim());
        }
    }

    /**
     * 获取提交文件的路径
     * @param projectUrl
     * @throws Exception
     */
    public static void doMain(String projectUrl) throws Exception {
        setupLibrary(projectUrl);
        final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        final Date begin = format.parse(beginTime);
        final Date end = format.parse(endTime);
        final List<String> history = new ArrayList<String>();
        final List<String> deleteHistory = new ArrayList<String>();
        //String[] 为过滤的文件路径前缀，为空表示不进行过滤
        repository.getOptions();
        repository.log(new String[]{""},
                startRevision,
                endRevision,
                true,
                true,
                new ISVNLogEntryHandler() {
                    public void handleLogEntry(SVNLogEntry svnlogentry)
                            throws SVNException {
                        if (svnlogentry.getDate().after(begin)
                                && svnlogentry.getDate().before(end)) {
                            // 依据提交人过滤
                            if (!"".equals(author)) {
                                if (author.equals(svnlogentry.getAuthor())) {
                                    fillResult(svnlogentry);
                                }
                            } else {
                                fillResult(svnlogentry);
                            }
                        }
                    }

                    public void fillResult(SVNLogEntry svnlogentry) {
                        //getChangedPaths为提交的历史记录MAP key为文件名，value为文件详情
                        Map<String, SVNLogEntryPath> changedPath = svnlogentry.getChangedPaths();
                        for (Map.Entry<String, SVNLogEntryPath> entry : changedPath.entrySet()) {
                            SVNLogEntryPath entryPath = entry.getValue();
                            if(entryPath.getType() == SVNLogEntryPath.TYPE_DELETED){
                                deleteHistory.add(entry.getKey());
                            }else{
                                history.add(entry.getKey());
                            }
                        }
                        readMe += svnlogentry.getMessage() +"\r\n";
                    }
                });
        overViewHistory(history,deleteHistory);
    }

    /**
     * 打包前预览
     * @param history
     */
    public static void overViewHistory(List<String> history,List<String> deleteHistory) throws Exception {
        int fileNum = history.size();
        if(fileNum > 0){
            System.out.println("准备打包文件：");
            packageHistory(history,deleteHistory);
        }else {
            System.out.println("没有找到要打包的文件,请检查过滤条件设置！");
        }
    }

    /**
     * 打包提交的文件
     * @param history
     */
    public static void packageHistory(List<String> history,List<String> deleteHistory) throws Exception {
        prepareTargetPackage();
        for (String path : history) {
            if(deleteHistory.indexOf(path) != -1){
                System.out.println("文件已被从svn上删除："+path);
                continue;
            }
            System.out.println("开始打包："+path);
            String loaclPath = buildPath;
            String targetPath = targetPackageFilePath + packageNamePer+packageName;
            if(path.endsWith("java")){
                loaclPath += classPathPer;
                targetPath += "\\web"+classPathPer;
                String classPath = path.split("java")[1];
                String fileName = classPath+"class";
                String _loaclPath = loaclPath + fileName;
                String _targetPath = targetPath + fileName;
                copyFile(_loaclPath,_targetPath);

                classPath = classPath.substring(0,classPath.length()-1);

//                System.out.println("classPath:"+classPath);
//                System.out.println("loaclPath:"+loaclPath);

//                String str = loaclPath+classPath;
                int index = classPath.lastIndexOf("/");
                String classPathTemp = classPath.substring(0,index);
                String sourcePath = loaclPath+classPathTemp;
                String targetFileName = classPath.substring(index+1,classPath.length());
                File sourceFile = new File(sourcePath);
                File[] files = sourceFile.listFiles();
                for (int i=0;i<files.length;i++){
                    File file = files[i];
                    String neededName = file.getName();
                    if(neededName.endsWith("class") && neededName.startsWith(targetFileName)){
                        copyFile(file.getAbsolutePath(),targetPath+classPathTemp+"/"+neededName);
                    }
                }
            }else if(path.endsWith("sql")){
                String sqlPath = "\\"+PackageExecutor.projectConfig.localSqlProjectName + path.split(PackageExecutor.projectConfig.svnSqlProjectName)[1] + (PackageExecutor.projectConfig.svnSqlProjectName.trim().equals("sql") ? "sql" : "");
                loaclPath = projectPath +sqlPath;
                targetPath += sqlPath;
                System.out.println(loaclPath);
                copyFile(loaclPath,targetPath);
            }else{
                String resourcePath = path.split("webapp")[1];
                loaclPath = loaclPath+resourcePath;
                targetPath = targetPath+"\\web"+resourcePath;
                copyFile(loaclPath,targetPath);
            }
        }
        if(history.size() > deleteHistory.size()){
            //添加说明文件
            addReadMe(readMe);
            ZipCompress zipCompress = new ZipCompress(targetPackageFilePath + packageNamePer+packageName+".zip",targetPackageFilePath + packageNamePer+packageName);
            zipCompress.zip();
        }else{
            System.out.println("没有需要打包的文件");
        }
    }

    /**
     * 初始化打包目录
     */
    public static void prepareTargetPackage(){
        File file = new File(targetPackageFilePath + packageNamePer +packageName);
        if(!file.exists()){
            file.mkdir();
        }
    }

    /**
     * 添加更新包的说明文档
     * @param readMe
     */
    public static void  addReadMe(String readMe){
        readMe += "\r\n";
        readMe += "代码信息：\r\n开始版本："+startRevision+"\r\n结束版本："+endRevision+"\r\n打包人："+author;
        if(null == readMe || readMe.trim().length() == 0){
            return;
        }
        File file = new File(targetPackageFilePath + packageNamePer +packageName+"/readMe.txt");
        FileInputStream fis = null;
        InputStreamReader isr=null;
        BufferedReader br = null;
        FileOutputStream fos = null;
        PrintWriter pw = null;
        if(!file.exists()){
            try {
                file.createNewFile();
                StringBuffer buffer = new StringBuffer();
                buffer.append(readMe);
                fos  = new FileOutputStream(file);
                pw = new PrintWriter(fos);
                pw.write(buffer.toString().toCharArray());
                pw.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(null != pw){
                    pw.close();
                }
                if(null != fos){
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

    /**
     * 复制文件
     * @param source
     * @param dest
     */
    public static void copyFile(String source, String dest){
        try {
            addTargetFilePath(dest);
            File targetFile = new File(dest);
            if (!targetFile.isDirectory()){
                copyFileUsingFileChannels(new File(source),targetFile);
                System.out.println("成功打包了："+dest);
            }
        }catch (Exception e){
            System.out.println("复制文件时发生了错误");
            System.out.println(source);
            System.out.println(dest);
            e.printStackTrace();
        }
    }

    /**
     * 使用文件流复制文件
     * @param source
     * @param dest
     * @throws IOException
     */
    private static void copyFileUsingFileStreams(File source, File dest)
            throws IOException {
        InputStream input = null;
        OutputStream output = null;
        try {
            input = new FileInputStream(source);
            output = new FileOutputStream(dest);
            byte[] buf = new byte[1024];
            int bytesRead;
            while ((bytesRead = input.read(buf)) > 0) {
                output.write(buf, 0, bytesRead);
            }
        } finally {
            input.close();
            output.close();
        }
    }

    /**
     * 使用通道复制文件
     * @param source
     * @param dest
     * @throws IOException
     */
    public static void copyFileUsingFileChannels(File source, File dest) throws IOException {
        FileChannel inputChannel = null;
        FileChannel outputChannel = null;
        try {
            inputChannel = new FileInputStream(source).getChannel();
            outputChannel = new FileOutputStream(dest).getChannel();
            outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
        } finally {
            inputChannel.close();
            outputChannel.close();
        }
    }
    /**
     * 创建文件夹
     * @param dest
     */
    public static void addTargetFilePath(String dest){
        int index = dest.lastIndexOf("/");
        String path = dest.substring(0,index);
        File targetFile = new File(path);
        if(!targetFile.exists()){
            targetFile.mkdirs();
        }
    }
}
